#include "PlainCodecStream.h"
#include "HuffmanCodecImpl.h"
#include "Tree.h"
#include "Node.h"

using namespace Huffman;

HuffmanCodecImpl::HuffmanCodecImpl(std::string inputFile, std::string outputFile) : HuffmanCodec(inputFile, outputFile)
{
	// copies the input and output file names
	this->inputFile = inputFile;
	this->outputFile = outputFile;

	// initilizes the symbol tree
	tree = new Tree();
}

HuffmanCodecImpl::~HuffmanCodecImpl(void)
{
	// empty descructor
}

void HuffmanCodecImpl::compress() 
{
	// TODO implement
}

/*
unsigned huff_decode (HCoder *huff)
{
unsigned node = 2 * huff->size - 1;

    //  work down the tree from the root
    //  until reaching either a leaf
    //     or the escape node

    while( node > huff->esc )
        if( arc_get1 () )
            node = huff->table[node].dnr;
        else
            node = huff->table[node].dnl;

    //  sent to the escape node???

    if( node == huff->esc )
        node = huff_readid (huff), huff_split (huff, node);

    //  increment weights and rebalance
    //  the coding tree

    huff_increment (huff, node);
    return node;
}
*/

// Algorithm:
// #1 find the node for the read symbol
// #2 if the symbol didn't existed then add it
// #3 increment the nodes in three
// #4 return the symbol associated with the given node
//
// Methods from orginal implementation
// - arc_get1()
// - huff_readid()
// - huff_split()
// - huff_increment()

void HuffmanCodecImpl::decompress() {

	// creates the input and outpu streams
	PlainCodecStream* input = new PlainCodecStream(this->inputFile);
	PlainCodecStream* output = new PlainCodecStream(this->outputFile);

	// reads the input by single character
	int inputChar;
	int decodedChar;

	Node* node;
	while((inputChar = input->read()) != -1) {

		// retrives the coresponding node for the given input character
		node = tree -> getNodeByVal(inputChar);		

		// if the node does not exist in the tree then add it
		if(node == 0) {
			// TODO should the tree nodes be splited?
			tree -> addNode(inputChar);			

			decodedChar = inputChar;
		} else {
			// otheriwse retrieves the coresponding symbol from the node
			decodedChar = node -> getSymbol();
		}

		// TODO increment the nodes weights
		tree -> incrementNodes(node);

		// output the encoded char
		output -> write(decodedChar);
	}

	// closes the streams
	input -> close();
	output -> close();

	// TODO add smart pointers instead of handling the memory on it's own
	delete output;
	delete input;
}